package com.lagou.edu.factory;

import com.lagou.edu.annotation.*;
import com.lagou.edu.service.TransferService;
import com.lagou.edu.utils.ClassUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String, Object> map = new HashMap<>();  // 存储对象单例池

    static {

        try {
           //根据xml查找该包下所有类
            List<String> classes = ClassUtils.getClassesFormPackage("beans.xml");
            //查找类注解初始化bean
            initClassMap(classes);
            //初始化字段赋值
            initField();
            //事务管理
            initTransactionCreate();
        } catch (Exception e) {
            e.printStackTrace();
        }

        
    }

    /**
     * 初始化bean
     * @param classes
     * @throws Exception
     */
    private static void initClassMap(List<String> classes) throws Exception {
        for (String className : classes) {
            Class<?> classInfo = Class.forName(className);
            Service Service = classInfo.getAnnotation(Service.class);
            Component Component = classInfo.getAnnotation(Component.class);
            Respository Respository = classInfo.getAnnotation(Respository.class);
            //只处理注解
            if (Service != null || Component != null || Respository != null) {
                String beanId = toLowerCaseFirstOne(classInfo.getSimpleName());
                try {
                    Object o = classInfo.newInstance();
                    Class<?>[] interfaces = classInfo.getInterfaces();
                    for (Class<?> anInterface : interfaces) {
                        String simpleName = anInterface.getSimpleName();
                        map.put(toLowerCaseFirstOne(simpleName), o);
                    }
                    map.put(beanId, o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 初始化字段值
     *
     * @throws IllegalAccessException
     */
    private static void initField() throws IllegalAccessException {
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        for (Map.Entry<String, Object> entity : entries) {
            Object object = entity.getValue();
            Field[] fields = entity.getValue().getClass().getDeclaredFields();
            if (fields != null && fields.length > 0) {
                //注入对象
                for (Field field : fields) {//遍历字段属性
                    if (field.isAnnotationPresent(Autowired.class)) {//判断Autowired注解
                        //设置private字段可赋值
                        field.setAccessible(true);
                        field.set(object, map.get(field.getName()));//注入set属性
                    }
                }
            }
        }

    }

    private static void initTransactionCreate() {
        ProxyFactory proxyFactory = (ProxyFactory) map.get("proxyFactory");
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            Object object = entry.getValue();
            Class<?> aClass = object.getClass();
            Transactional annotation = aClass.getAnnotation(Transactional.class);
            if (annotation != null) {//判断是否存在事务
                if (aClass.getInterfaces().length != 0) {//如果存在接口jdk动态代理
                    Object jdkProxy = proxyFactory.getJdkProxy(object);
                    map.put(entry.getKey(), jdkProxy);
                } else {
                    Object cglibProxy = proxyFactory.getCglibProxy(object);
                    map.put(entry.getKey(), cglibProxy);
                }
            }
        }

    }

    /**
     * 填充map
     *
     * @param value
     * @param className
     * @param clazz
     * @throws Exception
     */
    private static void classMapPutValue(String value, String className, Class clazz) throws Exception {
        map.put(toLowerCaseFirstOne(className), clazz.newInstance());
    }

    /**
     * 首字母转小写
     *
     * @param str
     * @return
     */
    private static String toLowerCaseFirstOne(String str) {
        if (Character.isLowerCase(str.charAt(0))) {
            return str;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
        }
    }

    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }
}
